'todo: Error handling!
'must load script 2-3 times before kicks in?
'increase performance by reading directly from lua table -> particles
'3D! OPENGL!? SceneGraph? K.I.S.S.
SuperStrict
Framework BRL.GLMax2D
Import Pub.Lua
Import BRL.Standardio
Import BRL.Map
Import BRL.Pngloader
Import BRL.Random
Import MaxGui.Drivers
Import BRL.EventQueue


import "..\common\guiwrapper.bmx"

Global LuaState:Byte Ptr
Include "torvaldraw_glue.bmx"
include "highlighter.bmx"


Global screen_width:Double = 600
Global screen_height:Double = 400
Global deltatime:Double = 0

Global script_errors:Int = 0
Global script_error_msg:String = ""

Global particleImg:TImage = CreateImage(8,8,DynamicImage|MaskedImage)
Global filenameSpriteMap:TMap = CreateMap()
Global spriteList:TList = CreateList()

Global scriptFile:String = "sidescroller2.lua"

Global window:TGadget = CreateWindow( "Messages", 100, 0, 300, 200 )
Global textarea:TGadget = CreateTextArea( 0, 0, ClientWidth(window), ClientHeight(window), window )
	SetGadgetLayout( textarea, EDGE_ALIGNED, EDGE_ALIGNED, EDGE_ALIGNED, EDGE_ALIGNED )
	SetGadgetText( textarea, "press F2 to load.~nF5 to refresh")
	ActivateGadget( textarea )
	

Global codeWindow:TGadget = CreateWindow( "code", 100, 300, 600, 600 )
Global codeText:TGadget = CreateTextArea( 0, 0, ClientWidth(codeWindow), ClientHeight(codeWindow), codeWindow)
	SetGadgetLayout( codeText, EDGE_ALIGNED, EDGE_ALIGNED, EDGE_ALIGNED, EDGE_ALIGNED )

	'local font:TGuifont = LoadGuiFont( "System Bold", 12.0 )
	'SetTextAreaFont codeText, font	

	SetTextAreaColor codeText, 0,0,0, True
	SetTextAreaColor codeText, 255,255,255, False 

	SetGadgetText( codeText, "")
	ActivateGadget( codeText)


Global Running% = True
type MainWindow extends IWindow
    Method OnClose( evt:TEvent )
        Super.OnClose( evt )
        Running = False
        Hide( )
    End Method

    Method OnMouseDown( evt:TEvent )
        Super.OnMouseDown( evt )
        SetStatusText( evt.x + ", "+evt.y )
    End Method

End Type

'Local mwindow:MainWindow = New MainWindow 
'mwindow.Create( Null, 64, 64, 512, 512, "TorvalDraw :)" )
'mwindow.Show( )


mainloop()


Function KillLuaState()
	If LuaState Then
		lua_close(LuaState)
		LuaState = Null
	EndIf
End Function

Function setProjection(perspProj:Int)
	glLoadIdentity();
	
	Local fov:Double = 50
	Local aspect:Double = Double(GraphicsWidth())/Double(GraphicsHeight())
	If(perspProj)
		gluPerspective( fov, aspect, 1.0, 100.0 )
	Else
		Local y:Double = 1 * fov/90.0
		Local x:Double = y * aspect
		glOrtho( -x, x, -y, y, 1.0, 100 )
	EndIf
	
	glMatrixMode(GL_MODELVIEW)
End Function


Function Mainloop()
	InitLuaState()
	
	'lua_getfield(LuaState, LUA_GLOBALSINDEX, "debug")' get global "debug" 
	'lua_getfield(LuaState, -1, "traceback")       ' get "debug.traceback" 
	'lua_remove (LuaState, -2)           ' remove "debug" table from stack 
	
	EnablePolledInput()
	AppTitle = "TorvalDraw"
	SetGraphicsDriver GLMax2DDriver()
	Graphics( Int(screen_width), Int(screen_height), 0 )
	drawCircleGradient(particleImg)

	
	Local time:Double = 0
	Local oldtime:Double = 0
	Local firstrun:Int = True
	Local Running:Int = True
	While Not AppTerminate() And Running
		PollEvent()
		
		Select EventID()
			Case EVENT_WINDOWCLOSE 
			  End
			Case EVENT_GADGETACTION
			  'Print CurrentEvent.ToString()
			  loadScript(True)
			Case EVENT_GADGETSELECT
				
				Local linepos:Int = TextAreaCursor(codeText,TEXTAREA_LINES) 'row
				Local cursorpos:Int = TextAreaCursor(codeText,TEXTAREA_CHARS) 'col
				'Local x:Int = TextAreaCharX( codeText, cursorpos )
				Local x:Int = cursorpos-TextAreaChar(codeText,linepos)
				SetStatusText codeWindow, ""+x+":"+linepos
				'SetStatusText codeWindow, ""+TextAreaText(codeText, cursorpos, TextAreaSelLen(codeText) )
			Default
		End Select

	
		Cls
		
		time = Double( MilliSecs() ) / 1000.0
		deltatime:Double = time-oldtime
		oldtime = time
		
		If KeyHit(KEY_F5) Then loadScript()
		
		If firstrun
			loadScript()
			firstrun = False
		EndIf
		
		If KeyHit(KEY_F2)
			getScriptFile()
			loadScript()
		EndIf
		
		If script_errors = False
			runScript() 
		Else
			SetGadgetText( textarea, script_error_msg )
			lua_pop(LuaState, 1); 'remove error state
		EndIf
		
		Flip
	Wend
	
	lua_close(LuaState)
	End
	
End Function

Function displayLuaScript()
	SetTextAreaText codeText, ""
	Local file:TStream = ReadFile(scriptFile)
	If Not file RuntimeError "could not open file "+scriptFile
	While Not Eof(file)
		AddTextAreaText codeText, ReadLine(file)+"~n"
	Wend
	CloseStream file
End Function

Function SplitString:TList(inString:String, Delim:String)
	Local tempList : TList = New TList
	Local currentChar : String = ""
	Local count : Int = 0
	Local TokenStart : Int = 0
	
	If Len(Delim)<1 Then Return Null
	
	inString = inString.Trim()
	
	For count = 0 Until Len(inString)
		If inString[count..count+1] = delim Then
			tempList.AddLast(inString[TokenStart..Count])
			TokenStart = count + 1
		End If
	Next
	tempList.AddLast(inString[TokenStart..Count])	
	Return tempList
End Function

Function clearFormatting()
	LockTextArea codeText
	FormatTextAreaText( codeText, 255,255,255, 0, 0 ,TextAreaLen(codeText) )
	UnlockTextArea codeText
End Function

function doHighlighting()
		Local txt:String = TextAreaText(codeText,0,TEXTAREA_ALL)	
		Local tot:Int = TextAreaLen(	codeText )
		
		HighlightRegion(codeText, txt , 0, tot)
end function

Function doHighlightingOLD()
	clearFormatting()
	LockTextArea codeText
	'Todo: 
	'my api
	'lua keywords
		Local keywords:String[] = ["break", "do", "end", "else", "elseif", "function", "if", "local", "nil", "not", "or", "repeat", "return", "then", "until", "while" ]
	
		Local txt:String = TextAreaText(codeText,0,TEXTAREA_ALL)	
		Local tot:Int = TextAreaLen(	codeText )
		
		HighlightRegion(codeText, txt , 0, tot)
		
		For Local keywd:String = EachIn keywords
		Local lookPos:Int = 0
		
		While lookPos < tot
		
		'how does bmax gui do the syntax highlighting?
		
		Rem
		Local foundLen:Int = 0
		Local foundPos:Int = 0
		For Local keywd:String = EachIn keywords
			foundPos = txt.Find(keywd,lookPos)
			If foundPos <> -1
				foundLen = keywd.length
				FormatTextAreaText( codeText, 0,168,232, 0, foundPos,foundLen )
				Exit 'found a keyword, increase lookpos
			EndIf
		Next
		lookPos = lookPos + 1
		End Rem
		
	
		lookPos = txt.Find(keywd,lookPos )
		If lookPos <> -1
			FormatTextAreaText( codeText, 255,255,0, 0, lookPos ,keywd.length)
		Else
			Exit
		EndIf
	

		
		lookPos :+1		
		
		Rem
		lookPos = txt.Find("bmxprintf",lookPos )
		If lookPos <> -1
			FormatTextAreaText( codeText, 255,255,0, 0, lookPos ,"bmxprintf".length)
		Else
			Exit
		EndIf
		lookPos :+1
		End Rem
		
		Wend
		Next
		
	UnlockTextArea codeText
End Function

Function loadScript(fromGadget:Int = False) 'expects graphics is setup
	KillLuaState()
	InitLuaState()
	
	
	Print "loading script..."
	Local Result:Int = 0
	If fromGadget
		Result = luaL_dostring(LuaState, GadgetText(codeText) )
	Else
		displayLuaScript()
		Result = luaL_dofile(LuaState, scriptFile)
	EndIf 
	
	If (Result <> 0) Then   ' ERROR!!!
		script_errors = True
		script_error_msg = lua_tostring( LuaState, -1 )
		SetGadgetText( textarea, script_error_msg )
		lua_pop(LuaState, 1); 'remove error msg
	Else
		script_errors = False
		script_error_msg = ""
		doHighlighting()
	End If
	
	WriteStdout ""
	
	If( script_errors = 0)
		checkFuncExists("setup")
		checkFuncExists("draw")
		
		'set frame variables before running 'setup()' and 'draw()'
		updateFrameVariables()
		callLuaFunc("setup")
	EndIf
End Function 

Function runScript()
	updateFrameVariables()	
	callLuaFunc("draw")
End Function

Function updateFrameVariables()
	lua_pushinteger(LuaState, GraphicsWidth() )
	lua_setglobal (LuaState, "xres")	

	lua_pushinteger(LuaState, GraphicsHeight() )
	lua_setglobal (LuaState, "yres")
	
	lua_pushinteger(LuaState, KeyDown(KEY_LEFT) )
	lua_setglobal (LuaState, "keyleft")
	lua_pushinteger(LuaState, KeyDown(KEY_RIGHT) )
	lua_setglobal (LuaState, "keyright")		
	lua_pushinteger(LuaState, KeyDown(KEY_UP) )
	lua_setglobal (LuaState, "keyup")	
	lua_pushinteger(LuaState, KeyDown(KEY_DOWN) )
	lua_setglobal (LuaState, "keydown")	

	lua_pushinteger(LuaState, KeyHit(KEY_SPACE) )
	lua_setglobal (LuaState, "keyspacehit")	

		
	lua_pushinteger(LuaState, MouseDown(1) )
	lua_setglobal (LuaState, "mouseleft")	

	lua_pushinteger(LuaState, MouseHit(1) )
	lua_setglobal (LuaState, "mouseLeftHit")	
		
	lua_pushinteger(LuaState, MouseHit(2) )
	lua_setglobal (LuaState, "mouseRightHit")	
	
	lua_pushinteger(LuaState, MouseHit(3) )
	lua_setglobal (LuaState, "mouseMiddleHit")
	
	lua_pushinteger(LuaState, MouseX() )
	lua_setglobal (LuaState, "mousx")	
	lua_pushinteger(LuaState, MouseY() )
	lua_setglobal (LuaState, "mousy")	
	
	lua_pushnumber(LuaState, deltatime )
	lua_setglobal (LuaState, "deltatime")
End Function

Function callLuaFunc( funcName:String)
	lua_getglobal( LuaState, funcName )
	If lua_type( LuaState, -1 ) = LUA_TFUNCTION Then
		If lua_pcall( LuaState, 0, 0, 0 ) Then
			script_error_msg = "runtime error:"+lua_tostring( LuaState, -1 )
			script_errors = 1
			'Local error:String = lua_tostring( LuaState, -1 )
			lua_pop( LuaState, 1 )
			'RuntimeError(error)
		EndIf
	Else
		lua_pop( LuaState, 1 )
	EndIf
	WriteStdout ""
End Function

Function checkFuncExists( funcName:String ) 
	'' only needed at first run
	lua_getglobal(LuaState, funcName);
	
	If  lua_isnil(LuaState, -1)
		script_error_msg = "function "+ funcName +" Not defined!" 
		script_errors = 1
		Return
	EndIf
	lua_pop( LuaState, 1 )
End Function 

Function drawCircleGradient(img:TImage)
	Local siz:Float = img.width
	Local center:Float = siz / 2.0
	Local px:TPixmap = LockImage(img)
   	For Local y:Int=0 Until siz
   	For Local x:Int=0 Until siz
     	 	Local t:Float = Sqr( (center-x)*(center-x) + (center-y)*(center-y) ) / center
		Local c:Int = 255-255*t
		If( c < 0 ) c = 0
		If( c > 255 ) c = 255
		Local argb:Int = (255 Shl 24) + c Shl 16 + c Shl 8 + c
		WritePixel px,x,y,argb      	
   	Next
	Next 
	UnlockImage particleImg
End Function

Function getScriptFile()
			Local filter:String="Lua script:lua;Text Files:txt;All Files:*"
			scriptFile=RequestFile( "Select Lua script",filter )
End Function
